--[[ ItemCompare by Rubin
most UI code from AddonProfiler by Sshadowed
]]
local lib = LibStub("LibItemBonus-2.0")

ItemCompare = {}
local IC = ItemCompare

local mainFrame, headerFrame
local rows, headers, items, comparisonData = {}, {}, {}, {}
local MAX_ITEMS = 8
local MAX_ROWS = 18
local ROW_HEIGHT = 20
local HEADER_COLUMN_WIDTH = 200
local COLUMN_WIDTH = 75
local SPACING = 10
local STATS = {}
STATS.bonuses = {
	"AGI",
	"INT",
	"STA",
	"SPI",
	"STR",
	"HEALTH",
	"MANA",
	"HEALTHREG",
	"MANAREG",
	"BASE_ARMOR",
	"ARMOR_BONUS",
	"CR_BLOCK",
	"BLOCKVALUE",
	"CR_DEFENSE",
	"CR_DODGE",
	"CR_PARRY",
	"CR_RESILIENCE",
	"ATTACKPOWER",
	"CR_ARMOR_PENETRATION",
	"CR_CRIT",
	"CR_EXPERTISE",
	"CR_HASTE",
	"CR_HIT",
	"SPELLPEN",
	"SPELLPOWER",
	"ARCANERES",
	"FIRERES",
	"FROSTRES",
	"NATURERES",
	"SHADOWRES"	
}
local statsToTrack = {}
statsToTrack.bonuses = {}

local relativeComparisons = true
local alwaysAbsoluteComparisons = {}
alwaysAbsoluteComparisons["Linked by"] = true
alwaysAbsoluteComparisons["Item Level"] = true
-- alwaysAbsoluteComparisons["Damage per second"] = true
-- alwaysAbsoluteComparisons["Red Socket"] = true
-- alwaysAbsoluteComparisons["Yellow Socket"] = true
-- alwaysAbsoluteComparisons["Blue Socket"] = true
alwaysAbsoluteComparisons["Socket Bonus"] = true

local function IsEquippable(item)
	_, _, _, _, _, _, _, _, itemEquipLoc, _ = GetItemInfo(item)
	return itemEquipLoc ~= ""
end

local function UpdateFrames()
	if( not mainFrame or not mainFrame:IsVisible() ) then return end
	
	FauxScrollFrame_Update(mainFrame.scroll, #comparisonData, MAX_ROWS - 1, ROW_HEIGHT)
	local offset = FauxScrollFrame_GetOffset(mainFrame.scroll)
	local rowID = 1
	
	for _, row in pairs(rows) do
		row.header:SetText("")
		for _, cell in pairs(row.slots) do
			cell:SetText("")
		end
	end
	
	for i=1, #headers do
		if items[i] and items[i].texture then
			headers[i].texture:SetTexture(items[i].texture)
			headers[i].texture:Show()
		else
			headers[i].texture:Hide()
		end
	end
	
	for i= 1+offset, #comparisonData do
		local row = rows[i-offset]
		local difference
		if row then
			if i > 0 and i <= #comparisonData then
				row.header:SetText(comparisonData[i][1] or "")
				for j=1, #items do
					if relativeComparisons and j ~= 1 and not alwaysAbsoluteComparisons[comparisonData[i][1]] then
						difference = (tonumber(comparisonData[i][j+1]) or 0) - (tonumber(comparisonData[i][1+1]) or 0)
						if difference < 0 then
							row.slots[j]:SetText("|cffff1919" .. difference .. "|r")
						elseif difference == 0 then
							row.slots[j]:SetText("0")
						elseif difference > 0 then
							row.slots[j]:SetText("|cff19ff19+" .. difference .. "|r")
						end
					else
						row.slots[j]:SetText(comparisonData[i][j+1])
					end
				end
			end
		end
		row:Show()
	end
end

local function CreateFrames()
	local backdrop = {
		bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
		edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",
		edgeSize = 1,
		insets = {left = 1, right = 1, top = 1, bottom = 1}}
	
	mainFrame = CreateFrame("Frame", "ItemCompare_Frame", UIParent)
	mainFrame:SetBackdrop(backdrop)
	mainFrame:SetBackdropColor(0, 0, 0, 0.90)
	mainFrame:SetBackdropBorderColor(0.75, 0.75, 0.75, 1)
	mainFrame:SetHeight((ROW_HEIGHT+SPACING/4)*MAX_ROWS)
	mainFrame:SetWidth(HEADER_COLUMN_WIDTH+COLUMN_WIDTH*MAX_ITEMS+SPACING)
	mainFrame:ClearAllPoints()
	mainFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
	mainFrame:SetFrameStrata("HIGH")
	mainFrame:SetMovable(true)
	table.insert(UISpecialFrames, "ItemCompare_Frame")
	
	mainFrame.scroll = CreateFrame("ScrollFrame", "ItemCompareFrameScroll", mainFrame, "FauxScrollFrameTemplate")
	mainFrame.scroll:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 0, -4)
	mainFrame.scroll:SetPoint("BOTTOMRIGHT", mainFrame, "BOTTOMRIGHT", -26, 3)
	mainFrame.scroll:SetScript("OnVerticalScroll", function(self, value) FauxScrollFrame_OnVerticalScroll(self, value, ROW_HEIGHT, AP.UpdateFrame) end)
	
	for id=1, MAX_ROWS do
		local row = CreateFrame("Frame", nil, mainFrame)
		row:SetWidth(HEADER_COLUMN_WIDTH + MAX_ITEMS*COLUMN_WIDTH)
		row:SetHeight(ROW_HEIGHT)
		row.header = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
		row.header:SetPoint("LEFT", row, "LEFT", 0, 0)
		row.header:SetJustifyH("LEFT")
		row.header:SetJustifyV("CENTER")
		row.header:SetWidth(HEADER_COLUMN_WIDTH)
		row.header:SetHeight(ROW_HEIGHT)
		row:Hide()
		
		row.slots = {}
		for slot=1, MAX_ITEMS do
			row.slots[slot] = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
			row.slots[slot]:SetJustifyH("LEFT")
			row.slots[slot]:SetJustifyV("CENTER")
			row.slots[slot]:SetWidth(COLUMN_WIDTH)
			if( slot > 1 ) then
				row.slots[slot]:SetPoint("TOPLEFT", row.slots[slot-1], "TOPLEFT", COLUMN_WIDTH, 0)
			else
				row.slots[slot]:SetPoint("TOPLEFT", row, "TOPLEFT", HEADER_COLUMN_WIDTH, -6)
			end
		end

		if( id > 1 ) then
			row:SetPoint("TOPLEFT", rows[id - 1], "BOTTOMLEFT", 0, -2)
		else
			row:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 4, -1)
		end

		rows[id] = row
	end
	
	headerFrame = CreateFrame("Frame", nil, mainFrame)
	headerFrame:SetBackdrop(backdrop)
	headerFrame:SetBackdropColor(0, 0, 0, 0.90)
	headerFrame:SetBackdropBorderColor(0.75, 0.75, 0.75, 1)
	headerFrame:SetHeight(50)
	headerFrame:SetWidth(mainFrame:GetWidth())
	headerFrame:ClearAllPoints()
	headerFrame:SetPoint("BOTTOMLEFT", mainFrame, "TOPLEFT", 0, SPACING)
	
	for slot=1, MAX_ITEMS do
		headers[slot] = CreateFrame("Button", "ItemCompareHeader" .. slot, headerFrame, "ItemButtonTemplate")
		headers[slot].texture = headers[slot]:CreateTexture("ItemCompareHeader" .. slot .. "Texture")
		headers[slot].texture:SetDrawLayer("BACKGROUND")
		headers[slot].texture:SetAllPoints()
		headers[slot]:EnableDrawLayer("BACKGROUND")
		headers[slot]:RegisterForClicks("LeftButtonUp", "RightButtonUp")
		headers[slot]:SetScript("OnClick", function(self, button)
			if IsShiftKeyDown() then
				if items[slot] then ChatEdit_InsertLink(items[slot].link) end
			else
				if button == "LeftButton" then
					ItemCompare.SetBaseItem(slot)
				else
					ItemCompare.RemoveItem(slot)
				end
			end
		end)
		headers[slot]:SetScript("OnEnter", function(self, motion)
			if items[slot] then
				GameTooltip:SetOwner(self)
				GameTooltip:SetHyperlink(items[slot].link)
			end
		end)
		headers[slot]:SetScript("OnLeave", function(self, motion)
			GameTooltip:Hide()
		end)
		if( slot > 1 ) then
			headers[slot]:SetPoint("TOPLEFT", headers[slot-1], "TOPLEFT", COLUMN_WIDTH, 0)
		else
			headers[slot]:SetPoint("TOPLEFT", headerFrame, "TOPLEFT", HEADER_COLUMN_WIDTH, -SPACING/2)
		end
	end
	
	local mover = CreateFrame("Frame", nil, headerFrame)
	mover:SetAllPoints(headerFrame)
	mover:SetMovable(true)
	mover:EnableMouse(true)
	mover:RegisterForDrag("LeftButton")
	mover:SetScript("OnDragStart", function(self)
		mainFrame:StartMoving()
	end)
	mover:SetScript("OnDragStop", function(self)
		mainFrame:StopMovingOrSizing()
	end)
	
	local closeButton = CreateFrame("Button", nil, mover, "UIPanelCloseButton")
	closeButton:SetPoint("TOPLEFT", SPACING, -SPACING)
	closeButton:SetScript("OnClick", function()
		HideUIPanel(mainFrame)
	end)
	
	mainFrame:Show()
	headerFrame:Show()
	UpdateFrames()
end

local function insertRow(field, label)
	local row = {}
	table.insert(row, label)
	for _, item in pairs(items) do
		table.insert(row, item[field] or "")
	end
	table.insert(comparisonData, row)
end

local function insertStat(stat, label)
	local row = {}
	table.insert(row, label)
	for _, item in pairs(items) do
		table.insert(row, item.stats[stat] or "")
	end
	table.insert(comparisonData, row)
end

local function insertBonus(bonus, label)
	local row = {}
	table.insert(row, label or lib.patterns.NAMES[bonus])
	for _, item in pairs(items) do
		table.insert(row, item.stats.bonuses[bonus] or "")
	end
	table.insert(comparisonData, row)
end

local function insertSocketBonus()
	local row = {}
	table.insert(row, "Socket Bonus")
	for _, item in pairs(items) do
		if item.stats.inactive_gem_bonus then
			for k, v in pairs(item.stats.inactive_gem_bonus) do
				if lib.patterns.NAMES[k] then table.insert(row, v .. " " .. lib.patterns.NAMES[k]) end
			end
		else
			table.insert(row, "")
		end
	end
	table.insert(comparisonData, row)
end

local function UpdateComparison()
	for i=#comparisonData, 1, -1 do table.remove(comparisonData, i) end
	for k, _ in pairs(statsToTrack.bonuses) do statsToTrack.bonuses[k] = nil end
	statsToTrack.source = nil
	statsToTrack.ilevel = nil
	statsToTrack.set = nil
	statsToTrack.dps = nil
	statsToTrack.socket_bonus = nil
	
	for i=1, #items do
		local item = items[i]
		if not item.stats then
			item.stats = lib:ScanItemLink(item.link)
		end
        for k,v in pairs(item.stats.bonuses) do statsToTrack.bonuses[k] = v end
		if item.source then statsToTrack.source = true end
		if item.stats.inactive_gem_bonus then statsToTrack.inactive_gem_bonus = true end
		if item.stats.set then statsToTrack.set = true end
		if item.stats.bonuses["WEAPON_MAX"] then
			-- lua doesn't have a math.round
			item.stats.dps = floor(((item.stats.bonuses["WEAPON_MAX"]+item.stats.bonuses["WEAPON_MIN"])/2 / item.stats.bonuses["WEAPON_SPEED"])*10 + 0.5)/10
			statsToTrack.dps = true
		end
		if item.stats.inactive_gem_bonus then statsToTrack.socket_bonus = true end
		_, _, _, item.stats.ilevel, _, _, _, _, _, item.texture = GetItemInfo(item.link)
		if item.stats.ilevel then statsToTrack.ilevel = true end
	end
	
	if statsToTrack.source then insertRow("source", "Linked by") end
	if statsToTrack.ilevel then insertStat("ilevel", "Item Level") end
	if statsToTrack.dps then insertStat("dps", "Damage per second") end
	for _, bonus in pairs(STATS.bonuses) do
		if statsToTrack.bonuses[bonus] then insertBonus(bonus) end
	end
	if statsToTrack.bonuses["EMPTY_SOCKET_RED"] then insertBonus("EMPTY_SOCKET_RED", "Red Socket") end
	if statsToTrack.bonuses["EMPTY_SOCKET_YELLOW"] then insertBonus("EMPTY_SOCKET_YELLOW", "Yellow Socket") end
	if statsToTrack.bonuses["EMPTY_SOCKET_BLUE"] then insertBonus("EMPTY_SOCKET_BLUE", "Blue Socket") end
	if statsToTrack.socket_bonus then insertSocketBonus() end
	
	local pawn_scales = PawnOptions and PawnOptions.Scales
	if pawn_scales then
		if #items ~= 0 then
			for scale, _ in pairs(pawn_scales) do
				for i=1, #items do
					local pawn_stats, pawn_socketBonusStats = PawnGetStatsForItemLink(items[i].link)
					items[i][scale] = PawnGetItemValue(pawn_stats, pawn_socketBonusStats, scale)
				end
				insertRow(scale, "Pawn: " .. scale)
			end
		end
	end
	
	UpdateFrames()
end

function ItemCompare.ToggleFrame()
	if not mainFrame then
		CreateFrames()
	elseif mainFrame:IsVisible() then
		mainFrame:Hide()
	else
		mainFrame:Show()
		UpdateFrames()
	end
end

function ItemCompare.AddItemToCompare(link, source)
	if #items == MAX_ITEMS or not IsEquippable(link) then return end
	local id = link:match("item:(%d+):")
	if id then
	     local _, link = GetItemInfo(id)
	     if link then
	          table.insert(items, { link=link, source=source})
	     end
	end
	UpdateComparison()
end

function ItemCompare.RemoveItem(slot)
	if slot > #items or slot < 1 or slot > MAX_ITEMS then return end
	table.remove(items, slot)
	UpdateComparison()
end

function ItemCompare.SetBaseItem(slot)
	if slot > #items or slot < 2 or slot > MAX_ITEMS then return end
	items[1], items[slot] = items[slot], items[1]
	UpdateComparison()
end

-- LinkWrangler support
local LW = LinkWrangler
if LW then
	local oldFunc = LW.ButtonClick
	LW.ButtonClick = function(button)
		if button.ButtonType == "Compare" and IsShiftKeyDown() then
			_, _, link, _, _, whisper = LW.GetLinkInfo(button:GetParent())
			ItemCompare.AddItemToCompare(link, whisper)
		else
			oldFunc(button)
		end
	end
end
-- end LinkWrangler support

local oldChatEdit_InsertLink = ChatEdit_InsertLink
ChatEdit_InsertLink = function(link, ...)
	if ItemCompare_Frame and ItemCompare_Frame:IsVisible() and not ChatFrameEditBox:IsVisible() then
		ItemCompare.AddItemToCompare(link)
	else
		oldChatEdit_InsertLink(link, ...)
	end
end

SLASH_ITEMCOMPARE1 = "/itemcompare"
SLASH_ITEMCOMPARE2 = "/ic"
SlashCmdList["ITEMCOMPARE"] = function(msg)
	if not msg or msg == "" then
		ItemCompare.ToggleFrame()
	else
		ItemCompare.AddItemToCompare(msg)
	end
end